﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;

namespace TA.Turbo.Controls
{
	/// <summary>
	/// Base class for all complex list controls.
	/// </summary>
	[ParseChildren(true), PersistChildren(false)]
	public abstract class BaseComplexListControl : BaseComplexValueControl<string>, IListControl
	{
		#region PUBLIC
		#region INIT
		/// <summary>
		/// Ctor.
		/// </summary>
		public BaseComplexListControl()
		{
			ListItemCollection lic = new ListItemCollection();
			lic._owner = this;
			ViewState["Items"] = lic;
		}
		#endregion
		#region PROPS
		#region DEF
		/// <summary>
		/// Props.
		/// </summary>
		protected static new Properties _clientProperties = Define(BaseFieldControl<string>._clientProperties, ListControlCommon.Properties);
		/// <summary>
		/// Props.
		/// </summary>
		public override Properties ClientProperties
		{
			get
			{
				return _clientProperties;
			}
		}
		#endregion
		/// <summary>
		/// List of top-level items in this list control (options and/or groups).
		/// </summary>
		[PersistenceMode(PersistenceMode.InnerProperty)]
		public ListItemCollection Items
		{
			get
			{
				return GetProperty<ListItemCollection>("Items");
			}
		}
		/// <summary>
		/// Gets all options in this list control (no groups).
		/// </summary>
		public ListItem[] Options
		{
			get
			{
				return ListControlCommon.GetOptions(this);
			}
		}
		/// <summary>
		/// The CSS class applied to all items which don't have a class individually specified for them.
		/// </summary>
		public string ItemCssClass
		{
			get
			{
				return this.GetProperty<string>("ItemCssClass");
			}
			set
			{
				this.ViewState["ItemCssClass"] = value;
			}
		}
		/// <summary>
		/// The CSS class applied to all groups which don't have a class individually specified for them.
		/// </summary>
		public string GroupCssClass
		{
			get
			{
				return this.GetProperty<string>("GroupCssClass");
			}
			set
			{
				this.ViewState["GroupCssClass"] = value;
			}
		}
		/// <summary>
		/// The items which are automatically inserted at the top of list when performing DataBind. If this is empty, no items will be inserted. Used for stuff like "Select a country" etc.
		/// </summary>
		[PersistenceMode(PersistenceMode.InnerProperty)]
		public List<ListItem> FirstItems
		{
			get
			{
				return this._firstItems;
			}
		}
		/// <summary>
		/// The items which are automatically inserted at the top of each category when performing DataBind. If this is empty, no items will be inserted. Used for stuff like "All in US" under the category "US", etc.
		/// </summary>
		[PersistenceMode(PersistenceMode.InnerProperty)]
		public List<ListItem> CategoryFirstItems
		{
			get
			{
				return this._categoryFirstItems;
			}
		}
		#endregion
		#region METHODS
		/// <summary>
		/// Creates the list items by enumerating the specified data source and using the specified value, text and category fields to set properties of the created list items.
		/// </summary>
		/// <param name="dataSource"></param>
		/// <param name="valueField"></param>
		/// <param name="textField"></param>
		/// <param name="categoryField"></param>
		public void DataBind(object dataSource, string valueField, string textField, string categoryField)
		{
			ListControlCommon.DataBind(this, dataSource, valueField, textField, categoryField);
		}
		/// <summary>
		/// Adds the first item to the collection which always precedes the data bound items.
		/// </summary>
		public virtual void AddFirstItems()
		{
			ListControlCommon.AddFirstItems(this);
		}
		#endregion
		#endregion
		#region INTERNAL
		#region VARS
		List<ListItem> _categoryFirstItems = new List<ListItem>(),
			_firstItems = new List<ListItem>();
		#endregion
		#region PROPS
		/// <summary>
		/// Gets or sets the serialized value of this control which is equal to the value since this is a string-valued control.
		/// </summary>
		protected internal override string SerializedValue
		{
			get
			{
				return this.Value;
			}
			set
			{
				this.Value = value;
			}
		}
		#endregion
		#region METHODS
		#region INIT
		/// <summary>
		/// Registers <see cref="Script.ListItem"/> and "BaseComplexListControl.js".
		/// </summary>
		protected internal override void RegisterIncludes(IncludeCollection includes)
		{
			base.RegisterIncludes(includes);

			ListControlCommon.RegisterIncludes(this, includes);
			includes.Add(new ScriptResourceInclude("TA.Turbo.Res.JS.ListControl.BaseComplexListControl.js", typeof(BaseComplexListControl)));
		}
		#endregion
		#region RENDER
		/// <summary>
		/// Renders the list items contained within this control.
		/// </summary>
		/// <param name="writer"></param>
		protected override void RenderContents(HtmlTextWriter writer)
		{
			ListControlCommon.RenderContents(this, writer);
		}
		/// <summary>
		/// Renders a group of items.
		/// </summary>
		/// <param name="writer"></param>
		/// <param name="item"></param>
		public void RenderItemGroup(System.Web.UI.HtmlTextWriter writer, ListItem item)
		{
			writer.RenderBeginTag(HtmlTextWriterTag.Label);
			writer.Write(item.Text);
			writer.RenderEndTag();

			RenderItemGroupBeginTag(writer, item);

			ListControlCommon.RenderItemGroupChildren(this, writer, item);

			writer.RenderEndTag();
		}
		/// <summary>
		/// When implemented, renders an item group's begin tag.
		/// </summary>
		/// <param name="writer"></param>
		/// <param name="item"></param>
		protected abstract void RenderItemGroupBeginTag(System.Web.UI.HtmlTextWriter writer, ListItem item);
		/// <summary>
		/// When implemented, renders one list item.
		/// </summary>
		/// <param name="writer"></param>
		/// <param name="item"></param>
		public abstract void RenderItemOption(System.Web.UI.HtmlTextWriter writer, ListItem item);
		#endregion
		#endregion
		#endregion
	}
}
